In many information processing applications, a server application running on a host or server computer in a distributed network provides processing services for client applications running on terminal or workstation computers of the network which are operated by a multitude of users. Common examples of such server applications include software for processing class registrations at a university, travel reservations, money transfers and other services at a bank, and sales at a business. In these examples, the processing services provided by the server application may update databases of class schedules, hotel reservations, account balances, order shipments, payments, or inventory for actions initiated by the individual users at their respective stations. This is sometimes referred to as client/server computing.
In a form of client/server computing sometimes known as “distributed objects,” the server application is developed as a set of components conforming to an object-oriented programming (OOP) model, such as the Microsoft Component Object Model (COM) and Distributed Component Object Model (DCOM), the IBM System Object Model (SOM), the Object Management Group's Common Object Request Broker Architecture (CORBA), and others. Object-oriented programming generally has advantages in ease of programming, extensibility, reuse of code, and integration of software from different vendors and (in some object-oriented programming models) across programming languages.
In object-oriented programming, programs are written as a collection of object classes which each model real world or abstract items by combining data to represent the item's properties with methods (e.g., program functions or procedures) to represent the item's functionality. More specifically, an object is an instance of a programmer-defined type referred to as a class, which exhibits the characteristics of data encapsulation, polymorphism and inheritance.
Data encapsulation refers to the combining of data (also referred to as properties of an object) with methods that operate on the data (also referred to as member functions of an object) into a unitary software component (i.e., the object), such that the object hides its internal composition, structure and operation and exposes its functionality to client programs that utilize the object only through one or more interfaces. An interface of the object is a group of semantically related methods of the object. In other words, the client programs do not access the object's data directly, but must instead call methods on the object's interfaces to operate on the data.
Polymorphism refers to the ability to view (i.e., interact with) two similar objects through a common interface, thereby eliminating the need to differentiate between two objects. Inheritance refers to the derivation of different classes of objects from a base class, where the derived classes inherit the properties and characteristics of the base class.
In distributed object and other client/server computing, it is often desirable and even crucial to coordinate processing activities on multiple computers, by separate processes on one computer, and even within a single process. For example, a money transfer operation in a banking application may involve updates to account information held in separate databases that reside on separate computers. These separate processing activities that form parts of a single logical operation are coordinated so as to take effect as a single indivisible unit of work, commonly referred to as a transaction. In many applications, performing sets of activities as a transaction becomes a business necessity. For example, if only one account is updated in a money transfer operation due to a system failure, the bank in effect creates or loses money for a customer. This coordination of data processing activities in client/server computing is sometimes referred to as on-line transaction processing.
More formally, a transaction is defined to be a collection of actions that conform to a set of properties (referred to as the “ACID” properties) which include atomicity, consistency, isolation, and durability. Atomicity means that all activities in a transaction either take effect together as a unit, or all fail. Consistency means that after a transaction executes, the system is left in a stable or correct state (i.e., if giving effect to the activities in a transaction would not result in a correct stable state, the system is returned to its initial pre-transaction state). Isolation means the transaction is not affected by any other concurrently executing transactions (accesses by transactions to shared resources are serialized, and changes to shared resources are not visible outside the transaction until the transaction completes). Durability means that the effects of a transaction are permanent and survive system failures. For additional background information on transaction processing, see, inter alia, Jim Gray and Andreas Reuter, Transaction Processing Concepts and Techniques, Morgan Kaufmann, 1993.
In client/server computing with “distributed objects,” the client program on the user's computer typically uses “real-time” or synchronous processing mechanisms to remotely invoke methods on the server application's objects that reside on the server computer, such as the remote procedure call (“RPC”). In a typical remote procedure call, object services of the operating system compile an interface definition language description of a server application object to generate a local “proxy” for the server application object on the client computer. The client software invokes methods of the remote server application object by issuing ordinary local procedure calls directly to the proxy. The proxy, in turn, utilizes RPC services to convey the procedure call to the actual server application object on the remote server computer. The RPC services marshal values for call parameters into a network message, and send the message via network protocols to the server computer. At the server computer, the RPC services unmarshal the call parameters and issue the call to the proper server application object method. The RPC services also marshal and unmarshal return values from the server application object method back to the client program via a network message.
The RPC services thus handle all the intricacies of network communications effectively “behind the scene,” such that the client program invokes the remote method in a similar manner to making a local procedure call. Like a local procedure call, execution of the client program is suspended (also known as “blocking”) during the RPC method invocation until the method completes and returns. This results in a synchronous flow of execution among the client program and server application objects.
In a prior patent application (hereafter “the Queued Method Invocations Patent”) of Dievendorff et al., entitled “Queued Method Invocations On Distributed Component Applications,” U.S. patent application Ser. No., 09/135,378, filed Aug. 17, 1998 (the disclosure of which is incorporated herein by reference), the inventors describe an alternative (termed, “queued components”) to real-time or synchronous method invocations (e.g., local and remote procedure calling) that provide a capability for a client of an object to issue and the object to receive method invocations on a queued basis using normal call semantics of an object model and without use of a message queuing API. The object framework or execution environment has services that automatically queue the method invocations, and at a potentially later time issue the queued method invocations to the object. Meanwhile, the client is allowed to continue execution without awaiting completion of the invoked method. Since method invocation queuing is performed transparently to the client and object in the object execution environment services, the client and object which are programmed to use normal call semantics can interact on either a real-time or queued basis, and effectively remain agnostic as to the basis on which the method invocations actually occur in the execution environment. Also, the queuing of the method invocations eliminates any need for the client and object to execute concurrently, which permits queued components to overcome limitations inherent to real-time synchronous method invocation mechanisms as to availability, object lifetimes and reference locality.
The particular implementation of queued components that is illustrated in the Queued Method Invocations Patent imposes a limitation that the client is not able to receive information back from the object via a return value or out parameters of any of the object's methods that is invoked through a queued method invocation. In other words, the queued method invocations are inherently unidirectional exchanges that transfer information only in one direction from the client to the object. The method invocation can have “in” parameters that contain input values for use by the object in executing the requested method. But, the invoked method is not allowed to have out parameters, such as pointers to locations for the object to store results of the method. This is because the client may no longer exist or no longer be available (e.g., where the client's and object's computers are no longer connected) when the queued method invocations are dispatched from the queue to the object.
Additionally, with respect to transaction processing in client/server computing, the implementation of transactional queued method invocations illustrated in the Queued Method Invocations Patent does not transmit the method invocations message to the object's message queue until the client's transaction commits. But, the implementation also ensures that all components that participate in the transaction (including the client) will have all terminated or become stateless before transaction commit completes. At a later time, the queued object is created in and processes the queued method invocations as part of a separate transaction. The client's lifetime thus always ends before the queued object's lifetime begins. Accordingly, due to this separation in the client and queued object's lifetimes, no information resulting from the invoked methods can be passed back from the object to the client.
A problem therefore with queued method invocations and like asynchronous calling mechanisms is how to obtain results of the invoked method without use of out parameters or return values.
A further obstacle for conveying results back to a requesting client application is that the several capabilities of queued components preferably are preserved. This includes that the queued object remains “agnostic” as to whether its methods are invoked through queued or synchronous method invocations. This means the queued object does not require explicit programming to handle queued method invocations, but rather interacts using normal method invocation and return semantics of the object model for both queued and synchronous interaction.
Yet another obstacle is that, in typical use of queued components, the queued object resides on a “server machine” in a distributed computer network and is invoked from possibly many client application programs residing on various client machines of the network. Preferably, the location of the client remains “transparent” to the queued object, meaning the queued object interacts with the client in the same way regardless of its location.